package com.recommend.recommendkeyword.service.impl;

import com.recommend.recommendkeyword.entity.Keywords;
import com.recommend.recommendkeyword.entity.LikeHistory;
import com.recommend.recommendkeyword.entity.RecommendKeyword;
import com.recommend.recommendkeyword.entity.SearchHistory;
import com.recommend.recommendkeyword.mapper.*;
import com.recommend.recommendkeyword.service.SearchService;
import com.recommend.recommendkeyword.vo.CompetitiveWordVO;
import com.recommend.recommendkeyword.vo.IntermediaryVO;
import com.recommend.recommendkeyword.vo.RecommendKeywordVO;
import org.apache.ibatis.javassist.compiler.ast.Keyword;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SearchServiceImpl implements SearchService {
    @Value("${pythonScriptPath}")
    String pythonScriptPath;
    @Value("${pythonInterpreter}")
    String pythonInterpreter;
    @Value("${srcSearchFilePath}")
    String srcSearchFilePath;
    @Value("${resultBaseUrl}")
    String resultBaseUrl;

    @Autowired
    KeyWordsMapper keyWordsMapper;
    @Autowired
    RecommendKeywordMapper recommendKeywordMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    SearchHistoryMapper searchHistoryMapper;
    @Autowired
    LikeHistoryMapper likeHistoryMapper;

    /**
     * 把一个```王者荣耀/online/中国/...```这样，用/分开的字符串变成一个List
     */
    // 泛型方法，支持返回 List<String> 或 List<Integer>
    public static <T> List<T> splitAndConvert(String input, Class<T> type) {
        // 使用 split 方法分割字符串
        String[] elements = input.split("/");

        // 根据目标类型转换
        if (type == String.class) {
            // 如果是 String 类型，直接转换为 List<String>
            return (List<T>) new ArrayList<>(Arrays.asList(elements));
        } else if (type == Integer.class) {
            // 如果是 Integer 类型，转换字符串数组为 Integer 列表
            return (List<T>) Arrays.stream(elements)
                    .map(Integer::valueOf) // 将字符串转换为整数
                    .collect(Collectors.toList());
        } else if (type == Double.class) {
            // 如果是 Double 类型，转换字符串数组为 Double 列表
            return (List<T>) Arrays.stream(elements)
                    .map(Double::valueOf) // 将字符串转换为浮点数
                    .collect(Collectors.toList());
        } else {
            throw new IllegalArgumentException("Unsupported type: " + type.getName());
        }
    }



    // 泛型方法，将两个长度相同的 List 组合成一个 Map
    public static <K, V> Map<K, V> combineListsToMap(List<K> keys, List<V> values) {
        if (keys.size() != values.size()) {
            throw new IllegalArgumentException("Keys and values lists must have the same size");
        }

        Map<K, V> resultMap = new HashMap<>();
        for (int i = 0; i < keys.size(); i++) {
            resultMap.put(keys.get(i), values.get(i));
        }
        return resultMap;
    }

    //调用py方法，将种子关键词对应的推荐词结果插入到数据库中
    public void usePythonScript(String seedKeyword) {
        try {
            // 对 URL 参数进行编码，防止特殊字符引发错误
            String encodedSrcSearchFilePath = URLEncoder.encode(srcSearchFilePath.replace("\\", "/"), StandardCharsets.UTF_8);  // 替换反斜杠并编码
            String encodedSeedKeyword = URLEncoder.encode(seedKeyword, StandardCharsets.UTF_8);  // 中文字符编码

            // 构造 URL 字符串
            String urlString = "http://127.0.0.1:8050/api/data?src_search_file_path=" + encodedSrcSearchFilePath + "&seed_keyword=" + encodedSeedKeyword;

            // 创建 HttpClient 对象
            HttpClient client = HttpClient.newHttpClient();

            // 创建 GET 请求
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(new URI(urlString))
                    .GET()
                    .header("Content-Type", "application/json")
                    .build();

            // 发送请求并获取响应
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

            // 输出响应内容
            System.out.println("Response Code: " + response.statusCode());
            if (response.statusCode() != 200) {
                System.out.println("Error: Received non-OK response code " + response.statusCode());
            }
            System.out.println("Response Body: " + response.body());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //将竞争词和中介词的文件转换成两个对应的字符串
    public List<String> convertFile(String filePath) {
        List<String> resultList = new ArrayList<>();

        // 定义两个 StringBuilder 用于拼接关键字和竞争度（中介词同理）
        StringBuilder keywordsBuilder = new StringBuilder();
        StringBuilder competitivenessBuilder = new StringBuilder();

        int lineCount = 0;  // 行计数器

        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            boolean isFirstLine = true; // 标记第一行（表头）

            while ((line = reader.readLine()) != null && lineCount < 11) {  // 读取前21行
                lineCount++;

                if (isFirstLine) {
                    // 跳过第一行表头
                    isFirstLine = false;
                    continue;
                }

                // 按制表符分割，提取关键字和竞争度
                String[] parts = line.split("\t");
                if (parts.length == 2) {
                    String keyword = parts[0];          // 提取关键字
                    String competitiveness = parts[1]; // 提取竞争度

                    // 拼接关键字和竞争度
                    if (keywordsBuilder.length() > 0) {
                        keywordsBuilder.append("/"); // 添加分隔符
                        competitivenessBuilder.append("/"); // 添加分隔符
                    }
                    keywordsBuilder.append(keyword);
                    competitivenessBuilder.append(competitiveness);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 转换为字符串
        String keywords = keywordsBuilder.toString();
        String competitiveness = competitivenessBuilder.toString();

        resultList.add(keywords);
        resultList.add(competitiveness);

        return resultList;
    }

    //根据原来和新的两个List，分别获取原来有，现在没有的集合的List；原来和现在都有的集合的List；原来没有，现在有的List
    public static <T> List<List<T>> compareLists(List<T> originalList, List<T> currentList) {
        // 使用 HashSet 来提高查找效率
        Set<T> originalSet = new HashSet<>(originalList);
        Set<T> currentSet = new HashSet<>(currentList);

        // 原来有，现在没有
        List<T> removed = new ArrayList<>(originalSet);
        removed.removeAll(currentSet);

        // 原来和现在都有
        List<T> common = new ArrayList<>(originalSet);
        common.retainAll(currentSet);

        // 原来没有，现在有
        List<T> added = new ArrayList<>(currentSet);
        added.removeAll(originalSet);

        // 返回结果
        List<List<T>> result = new ArrayList<>();
        result.add(removed); // 原来有，现在没有
        result.add(common);  // 原来和现在都有
        result.add(added);   // 原来没有，现在有
        return result;
    }

    /**
     * 根据种子关键词产生搜索结果
     */
    public RecommendKeywordVO getResultBySeed(Keywords keywords, int searchUserId) {
        // 获取关键词和对应的属性
        List<Integer> recommendIdList = splitAndConvert(keywords.getRecommendIdList(), Integer.class);
        List<Double> competitivenessList = splitAndConvert(keywords.getCompetitiveness(), Double.class);
        List<Integer> intermediaryIdList = splitAndConvert(keywords.getIntermediary(), Integer.class);
        List<Double> weightList = splitAndConvert(keywords.getWeight(), Double.class);

        // 将竞争关键词和竞争度组合成 map
        Map<Integer, Double> recommendCompetitivenessMap = combineListsToMap(recommendIdList, competitivenessList);
        Map<Integer, Double> intermediaryWeightMap = combineListsToMap(intermediaryIdList, weightList);

        // 按竞争度降序排序推荐关键词 ID
        List<Map.Entry<Integer, Double>> sortedRecommendEntries = recommendCompetitivenessMap.entrySet().stream()
                .sorted((e1, e2) -> Double.compare(e2.getValue(), e1.getValue())) // 按值降序
                .toList();

        // 按权重降序排序中介关键词 ID
        List<Map.Entry<Integer, Double>> sortedIntermediaryEntries = intermediaryWeightMap.entrySet().stream()
                .sorted((e1, e2) -> Double.compare(e2.getValue(), e1.getValue())) // 按值降序
                .toList();

        // 最终返回的竞争词列表和中介词列表
        List<CompetitiveWordVO> recommendList = new ArrayList<>();
        List<IntermediaryVO> intermediaryList = new ArrayList<>();

        // 填充竞争词列表
        for (Map.Entry<Integer, Double> entry : sortedRecommendEntries) {
            Integer recommendId = entry.getKey();
            Double competitiveness = entry.getValue();

            RecommendKeyword recommendKeyword = recommendKeywordMapper.getWordById(recommendId);
            // 查找 likeHistory 表，看用户是否点赞 (op为0无/1点赞/2点踩)
            LikeHistory userLike = likeHistoryMapper.getHistoryByUserAndWord(searchUserId, recommendId);
            int op = userLike != null ? userLike.getType() : 0;
            CompetitiveWordVO competitiveWordVO = new CompetitiveWordVO(
                    recommendId,
                    recommendKeyword.getSeedKeyword(),
                    recommendKeyword.getRecommendName(),
                    recommendKeyword.getThumbUp(),
                    recommendKeyword.getThumbDown(),
                    recommendKeyword.getCommentNum(),
                    recommendKeyword.getUserId(),
                    recommendKeyword.getType(),
                    competitiveness, // 确保竞争度正确映射
                    op
            );
            recommendList.add(competitiveWordVO);
        }

        // 填充中介词列表
        for (Map.Entry<Integer, Double> entry : sortedIntermediaryEntries) {
            Integer intermediaryId = entry.getKey();
            RecommendKeyword intermediaryKeyword = recommendKeywordMapper.getWordById(intermediaryId);
            // 查找 likeHistory 表，看用户是否点赞 (op为0无/1点赞/2点踩)
            LikeHistory userLike = likeHistoryMapper.getHistoryByUserAndWord(searchUserId, intermediaryId);
            int op = userLike != null ? userLike.getType() : 0;
            IntermediaryVO intermediaryVO = new IntermediaryVO(
                    intermediaryId,
                    intermediaryKeyword.getSeedKeyword(),
                    intermediaryKeyword.getRecommendName(),
                    intermediaryKeyword.getThumbUp(),
                    intermediaryKeyword.getThumbDown(),
                    intermediaryKeyword.getCommentNum(),
                    intermediaryKeyword.getUserId(),
                    intermediaryKeyword.getType(),
                    op
            );
            intermediaryList.add(intermediaryVO);
        }

        // 返回最终结果
        return new RecommendKeywordVO(keywords.getSeedKeyword(), recommendList, intermediaryList);
    }


    /**
     * 竞争词，中介词搜索（竞争度降序排序）
     */
    @Override
    public RecommendKeywordVO searchByComp(String seedKeyword, int searchUserId) {
        //先调用py函数，生成种子词对应的竞争词和种中介词的文件
        usePythonScript(seedKeyword);

        //然后读取文件，获得竞争关键词和中介关键词
        String competitivenessPath = resultBaseUrl + "\\\\" + seedKeyword + "\\\\" + seedKeyword + "_competitiveness_results.txt";
        String medWeightPath = resultBaseUrl + "\\\\" + seedKeyword + "\\\\" + seedKeyword + "_med_and_weight.txt";
        //list[0]是词的组合，把它变成id组合然后插入到关键词表中去;list[1]是竞争度/权重的组合，直接插入到数据库中
        List<String> competitivenessResultList = convertFile(competitivenessPath);
        List<String> medWeightResultList = convertFile(medWeightPath);

        //先获得竞争/中介词的list和竞争度/权重list
        List<String> competitiveWordList = splitAndConvert(competitivenessResultList.get(0), String.class);
        List<String> intermediaryWordList = splitAndConvert(medWeightResultList.get(0), String.class);
        List<Double> newComptitivenessList = splitAndConvert(competitivenessResultList.get(1), Double.class);
        List<Double> newWeightList = splitAndConvert(medWeightResultList.get(1), Double.class);
        System.out.println("新的竞争词List:" + competitiveWordList);
        System.out.println("新的中介词List:" + intermediaryWordList);
        System.out.println("新的竞争度List:" + newComptitivenessList);
        System.out.println("新的权重List:" + newWeightList);

        String competitiveIdString = "";
        String intermediaryIdString = "";

        //读取完文件之后，此时判断数据库中种子关键词是否存在，如果不存在的话新建，如果存在的话则更新
        if(keyWordsMapper.getKeywordBySeed(seedKeyword) == null) {
            System.out.println("种子关键词" + seedKeyword + "不存在");
            for (String competitiveWord : competitiveWordList) {
                recommendKeywordMapper.insertKeyword(seedKeyword, competitiveWord, searchUserId, 1);
                //然后将id进行组合
                RecommendKeyword recommendKeyword = recommendKeywordMapper.getWordBySeedAndRecommend(competitiveWord, seedKeyword);
                competitiveIdString = competitiveIdString + recommendKeyword.getRecommendId() + "/";
            }
            //去掉末尾的/
            competitiveIdString = competitiveIdString.substring(0, competitiveIdString.length() - 1);


            for (String intermediary : intermediaryWordList) {
                recommendKeywordMapper.insertKeyword(seedKeyword, intermediary, searchUserId, 0);
                //然后将id进行组合
                RecommendKeyword recommendKeyword = recommendKeywordMapper.getWordBySeedAndRecommend(intermediary, seedKeyword);
                intermediaryIdString = intermediaryIdString + recommendKeyword.getRecommendId() + "/";
            }
            intermediaryIdString = intermediaryIdString.substring(0, intermediaryIdString.length() - 1);

            System.out.println("竞争词Id字符串，competitiveIdString:" + competitiveIdString);
            System.out.println("中介词Id字符串，intermediaryIdString:" + intermediaryIdString);
            System.out.println("竞争度字符串，competitivenessResultList.get(1):" + competitivenessResultList.get(1));
            System.out.println("权重字符串，medWeightResultList.get(1):" + medWeightResultList.get(1));

            //将新的种子关键词插入到keywords表
            keyWordsMapper.insertKeyword(seedKeyword, competitiveIdString, competitivenessResultList.get(1),
                    intermediaryIdString, medWeightResultList.get(1));
        } else {
            System.out.println("种子关键词" + seedKeyword + "存在");
            //先获取原来有，现在没有的集合的List；原来和现在都有的集合的List；原来没有，现在有的List
            Keywords keywords = keyWordsMapper.getKeywordBySeed(seedKeyword);
           //先拿到原来的推荐关键词和中介关键词的列表
            List<Integer> recommendIdList = splitAndConvert(keywords.getRecommendIdList(), Integer.class);
            List<Double> competitivenessList = splitAndConvert(keywords.getCompetitiveness(), Double.class);
            List<Integer> intermediaryIdList = splitAndConvert(keywords.getIntermediary(), Integer.class);
            List<Double> weightList = splitAndConvert(keywords.getWeight(), Double.class);

            List<String> recommendWordList1 = new ArrayList<>();
            List<String> intermediaryWordList1 = new ArrayList<>();

            //数据库中种子关键词对应的竞争词列表和中介词列表
            for(Integer recommendId:recommendIdList)
                recommendWordList1.add(recommendKeywordMapper.getWordById(recommendId).getRecommendName());
            for(Integer intermediaryId:intermediaryIdList)
                intermediaryWordList1.add(recommendKeywordMapper.getWordById(intermediaryId).getRecommendName());
            // 调用方法进行比较
            List<List<String>> compResult = compareLists(recommendWordList1, competitiveWordList);
            List<List<String>> interResult = compareLists(intermediaryWordList1, intermediaryWordList);

            //原来有，现在没有：删除对应位置的竞争关键词id和竞争度，还有推荐关键词
            for(String compName: compResult.get(0)){
                RecommendKeyword recommendKeyword = recommendKeywordMapper.getWordBySeedAndRecommend(seedKeyword, compName);
                int index = recommendWordList1.indexOf(compName);
                recommendIdList.remove(index);
                competitivenessList.remove(index);
                recommendKeywordMapper.removeById(recommendKeyword.getRecommendId());
            }
            for(String interName: interResult.get(0)){
                RecommendKeyword recommendKeyword = recommendKeywordMapper.getWordBySeedAndRecommend(seedKeyword, interName);
                int index = intermediaryWordList1.indexOf(interName);
                intermediaryIdList.remove(index);
                weightList.remove(index);
                recommendKeywordMapper.removeById(recommendKeyword.getRecommendId());
            }

            //原来没有，现在有：新建对应的recommendKeyword，然后加入到keywords中
            String tempCompIdString = keyWordsMapper.getKeywordBySeed(seedKeyword).getRecommendIdList();
            String compString = keyWordsMapper.getKeywordBySeed(seedKeyword).getCompetitiveness();
            for(String compName: compResult.get(2)){
                recommendKeywordMapper.insertKeyword(seedKeyword, compName, searchUserId, 1);
                //然后将id进行组合，竞争词的id和竞争度的组合,修改种子关键词的竞争词id和竞争度
                RecommendKeyword recommendKeyword = recommendKeywordMapper.getWordBySeedAndRecommend(compName, seedKeyword);
                tempCompIdString = tempCompIdString + "/" + recommendKeyword.getRecommendId();
                int index = competitiveWordList.indexOf(compName);
                compString = compString + "/" + newComptitivenessList.get(index);
            }

            String tempInterIdString = keyWordsMapper.getKeywordBySeed(seedKeyword).getIntermediary();
            String weightString = keyWordsMapper.getKeywordBySeed(seedKeyword).getWeight();
            for(String interName: interResult.get(2)){
                recommendKeywordMapper.insertKeyword(seedKeyword, interName, searchUserId, 0);
                //然后进行中介关键词id和权重的组合，并进行修改
                RecommendKeyword recommendKeyword = recommendKeywordMapper.getWordBySeedAndRecommend(interName, seedKeyword);
                tempInterIdString = tempInterIdString + "/" + recommendKeyword.getRecommendId();
                int index = intermediaryWordList.indexOf(interName);
                weightString = weightString + "/" + newWeightList.get(index);
            }
            //然后修改新的关键词/中介词id，新的竞争度和权重
            keyWordsMapper.updateInfo(keywords.getKeywordId(), tempCompIdString, compString, tempInterIdString, weightString);
        }
        //此时插入表完毕
        Keywords keywords = keyWordsMapper.getKeywordBySeed(seedKeyword);
        // 修改用户搜索次数,关键词被搜索次数
        userMapper.addSearchNum(searchUserId);
        keyWordsMapper.addSearchNum(keywords.getKeywordId());

        //增加修改历史表记录
        Timestamp now = new Timestamp(System.currentTimeMillis());
        searchHistoryMapper.insertHistory(searchUserId, keywords.getKeywordId(), now);

        return getResultBySeed(keywords,searchUserId);
    }

    @Override
    public List<RecommendKeywordVO> searchHistory(int userId){
        List<SearchHistory> searchHistoryList = searchHistoryMapper.getUserHistory(userId);
        List<RecommendKeywordVO> recommendKeywordVOList = new ArrayList<>();
        for(SearchHistory searchHistory: searchHistoryList){
            Keywords keywords = keyWordsMapper.getKeywordById(searchHistory.getKeywordId());
            RecommendKeywordVO result = getResultBySeed(keywords ,userId);
            recommendKeywordVOList.add(result);
        }
        return recommendKeywordVOList;
    }

}
